import { BlockEnum } from '@/components/workflow/types'
import axios from '@/controllers/request'
import clsx, { ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
import { APITemplateType } from '../types/api'
import { checkUpperWords } from '../utils'

export function classNames(...classes: Array<string>): string {
  return classes.filter(Boolean).join(' ')
}

export function downloadFile(url, label) {
  return axios
    .get(url, { responseType: 'blob' })
    .then((res: any) => {
      const blob = new Blob([res.data])
      const link = document.createElement('a')
      link.href = URL.createObjectURL(blob)
      link.download = label
      link.click()
      URL.revokeObjectURL(link.href)
    })
    .catch(console.error)
}

export const downloadFileByUrl = function (fileUrl, fileName) {
  const a = document.createElement('a')
  a.href = fileUrl
  a.download = fileName
  a.style.display = 'none'
  document.body.appendChild(a)
  a.click()
  a.remove()
}

export async function downloadFileByUrl2(fileUrl, fileName) {
  try {
    const response = await fetch(fileUrl)
    if (!response.ok) {
      throw new Error('Network response was not ok')
    }
    const blob = await response.blob()
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.setAttribute('download', fileName) // or any other filename
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link) // clean up the element
    window.URL.revokeObjectURL(url) // cleanup the URL object
  } catch (error) {
    console.error('Error downloading file:', error)
  }
}

export function downloadJson(content) {
  const jsonStr = JSON.stringify(content)
  const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(jsonStr)}`

  const link = document.createElement('a')
  link.href = jsonString
  link.download = 'sample.json'

  link.click()
}

export function cn(...inputs: ClassValue[]): string {
  return twMerge(clsx(inputs))
}

// 交集
export function intersectArrays(...arrays) {
  if (arrays.length === 0) {
    return []
  }

  // 使用第一个数组作为基准
  const baseArray = arrays[0]

  // 过滤出基准数组中的元素，这些元素在其他所有数组中都存在
  const intersection = baseArray.filter(element => {
    return arrays.every(array => array.includes(element))
  })

  return intersection
}

// 时间戳转换 天时分秒（dhms）
export function formatMilliseconds(ms: number, format: string): string {
  const secondsInMillisecond = 1
  const minutesInMillisecond = secondsInMillisecond * 60
  const hoursInMillisecond = minutesInMillisecond * 60
  const daysInMillisecond = hoursInMillisecond * 24

  const days = Math.floor(ms / daysInMillisecond)
  const remainingHours = ms % daysInMillisecond
  const hours = Math.floor(remainingHours / hoursInMillisecond)
  const remainingMinutes = remainingHours % hoursInMillisecond
  const minutes = Math.floor(remainingMinutes / minutesInMillisecond)
  const remainingSeconds = remainingMinutes % minutesInMillisecond
  const seconds = Math.floor(remainingSeconds / secondsInMillisecond)

  let formattedString = format.replace('dd', days.toString())
  formattedString = formattedString.replace('hh', hours.toString())
  formattedString = formattedString.replace('mm', minutes.toString())
  formattedString = formattedString.replace('ss', seconds.toString())

  // Remove any extra spaces
  // formattedString = formattedString.replace(/\s+/g, ' ').trim();

  return formattedString
}

export function toTitleCase(str: string | undefined): string {
  if (!str) return ''
  const result = str
    .split('_')
    .map((word, index) => {
      if (index === 0) {
        return checkUpperWords(word[0].toUpperCase() + word.slice(1).toLowerCase())
      }
      return checkUpperWords(word.toLowerCase())
    })
    .join(' ')

  return result
    .split('-')
    .map((word, index) => {
      if (index === 0) {
        return checkUpperWords(word[0].toUpperCase() + word.slice(1).toLowerCase())
      }
      return checkUpperWords(word.toLowerCase())
    })
    .join(' ')
}

export function getFieldTitle(template: APITemplateType, templateField: string): string {
  return template[templateField].display_name
    ? template[templateField].display_name!
    : template[templateField].name
    ? toTitleCase(template[templateField].name!)
    : toTitleCase(templateField)
}

/* 转换类型 number123转中文一二三 */
export function digitToChinese(digit) {
  const chineseNums = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
  const chineseUnits = ['', '十', '百', '千', '万', '十', '百', '千', '亿']
  let str = ''
  let unitIndex = 0

  for (let i = digit.toString().length - 1; i >= 0; i--) {
    const currentDigit = digit.toString()[i]
    str = chineseNums[currentDigit] + (currentDigit !== '0' ? chineseUnits[unitIndex] : '') + str

    // 处理特殊情况，避免连续的“零”
    if (str.startsWith('零') && str.length > 1 && str[1] !== '零') {
      str = str.substring(1)
    }

    unitIndex++
  }

  // 移除开头的“零”
  str = str.replace(/^零+/, '')

  return str
}

export function fileSizeFormat(bytes) {
  if (!bytes) {
    return ''
  }
  if (bytes < 1024) {
    return bytes + ' B'
  } else if (bytes < 1024 * 1024) {
    return (bytes / 1024).toFixed(2) + ' KB'
  }
  return (bytes / (1024 * 1024)).toFixed(2) + ' MB'
}

export function convertBase64ToBlob(base64Data) {
  const byteCharacters = atob(base64Data)
  const byteNumbers = new Array(byteCharacters.length)
  for (let i = 0; i < byteCharacters.length; i++) {
    byteNumbers[i] = byteCharacters.charCodeAt(i)
  }
  const byteArray = new Uint8Array(byteNumbers)
  // 创建Blob对象
  const blob = new Blob([byteArray], { type: 'image/png' })
  return blob
}

export function blobToArrayBuffer(blob, callback) {
  const fileReader = new FileReader()
  fileReader.onload = function () {
    callback(this.result)
  }
  fileReader.readAsArrayBuffer(blob)
}

/**
 *
 * @param value
 * @description 4位数使用千分符号隔开
 * @returns string
 */
export const formatMaxValue = value => {
  if (value == null) return value
  if (Number.isNaN(+value)) return value
  return `${value}`.replace(/(\d{1,3})(?=(\d{3})+(?:$|\.))/g, '$1,')
}

// 将ArrayBuffer转换为Base64
export function arrayBufferToBase64(buffer) {
  let binary = ''
  const bytes = new Uint8Array(buffer)
  const chunkSize = 0x8000 // 32KB
  let index = 0

  while (index < bytes.length) {
    const chunk = bytes.subarray(index, Math.min(bytes.length, index + chunkSize))
    binary += String.fromCharCode.apply(null, chunk)
    index += chunkSize
  }

  return btoa(binary)
}

/* 正则获取{{}} 模型输入内容返回对于id and variable */
export function extractTemplateVariables(inputString: string): { id: string; variable: string }[] {
  // 定义正则表达式来匹配 {{#...#}} 模式
  const regex = /\{\{#(\w+)\.(\w+)#\}\}/g
  let match
  const result: { id: string; variable: string }[] = []

  // 使用 exec 方法循环查找所有匹配项
  while ((match = regex.exec(inputString)) !== null) {
    // match[1] 是 id, match[2] 是 variable
    if (match[1] && match[2]) {
      result.push({ id: match[1], variable: match[2] })
    }
  }

  return result
}
export interface VariableInfo {
  id: string
  variable: string
  tempName: string
}

export interface NodeVariable {
  id: string
  type: string
  label?: string
  value?: any
  default?: any
  required?: boolean
  variable: string
  max_length?: number
  [key: string]: any
}

export interface NodeOutput {
  type: string
  value: any
  variable: string
  [key: string]: any
}

export interface Node {
  id: string
  variables?: NodeVariable[]
  outputList?: NodeOutput[]
  [key: string]: any
}

/* 匹配flowVariables 重置当前模块的startVariables */
export function matchVariablesToNodes(
  templateVars: VariableInfo[],
  nodes: { [key: string]: Node }
): (NodeVariable | NodeOutput)[] {
  const matchedVariables: (NodeVariable | NodeOutput)[] = []

  templateVars.forEach(({ id, variable }) => {
    const node = nodes[id]
    if (node) {
      // 检查 variables 数组 = 开始节点
      if (node.variables) {
        const varMatch = node.variables.find(v => v.variable === variable)
        if (varMatch) {
          matchedVariables.push(varMatch)
        }
      }

      // 如果没有找到，则检查 outputList 数组 = 大模型节点
      if (node.outputList) {
        const outputMatch = node.outputList.find(o => o.variable === variable)
        if (outputMatch) {
          matchedVariables.push(outputMatch)
        }
      }
    }
  })

  // 去重
  return matchedVariables.filter((item, index, self) => index === self.findIndex(t => t.id === item.id))
}

export function matchVariablesToNodesV2(
  templateVars: VariableInfo[],
  nodes: { [key: string]: Node }
): (NodeVariable | NodeOutput)[] {
  const matchedVariables: (NodeVariable | NodeOutput)[] = []

  templateVars.forEach(({ id, variable, tempName }) => {
    const node = nodes[id]
    if (node) {
      // 检查 variables 数组 = 开始节点
      if (node.type === BlockEnum.Start && node.variables) {
        const varMatch = node.variables.find(v => v.variable === variable)
        if (varMatch) {
          matchedVariables.push({
            ...varMatch,
            nodeId: id,
            tempName
          })
        }
      }

      // 如果没有找到，则检查 outputList 数组 = 大模型节点
      // if (node.type === BlockEnum.LLM && node.outputList) {
      if (node.outputList) {
        const outputMatch = node.outputList.find(o => o.variable === variable)
        if (outputMatch) {
          matchedVariables.push({
            ...outputMatch,
            nodeId: id,
            tempName
          })
        }
      }
    }
  })

  // 去重
  return matchedVariables.filter((item, index, self) => index === self.findIndex(t => t.id === item.id))
}

/* id生成 */
export function generateUUIDv4() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    const r = crypto.getRandomValues(new Uint8Array(1))[0] % 16 | 0
    const v = c === 'x' ? r : (r & 0x3) | 0x8
    return v.toString(16)
  })
}

/* 输入id匹配 获取前缀title */
export const replaceIdWithTitle = (inputStr, flow) => {
  if (!inputStr || typeof inputStr !== 'string') return inputStr // 如果输入无效直接返回

  if (!inputStr.includes('.')) return inputStr // 如果没有"."直接返回

  const [idPart, rest] = inputStr.split('.', 2) // 分割字符串
  const node = Object.values(flow).find((n: any) => n.id === idPart) as any // 查找匹配的节点

  if (node && node.title) {
    return `${node.title}.${rest}` // 替换为"title.rest"
  }
  return inputStr // 如果找不到匹配的节点，保持原样
}
